package com.xjd.edu.toolkit.helper;

import cn.hutool.core.date.DateTime;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import javax.validation.constraints.NotNull;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Objects;

/**
 * 皮皮定制JDK日期类，默认时区为东八区 (Asia/Shanghai)
 *
 * @author wangyu
 * @since 2022/4/2
 */
public class GameDateTime {

    public static final ZoneId DEFAULT_ZONE_ID = ZoneId.of("Asia/Shanghai");
    public static final ZoneOffset DEFAULT_ZONE_OFFSET = ZoneOffset.ofHours(8);

    public static final DateTimeFormatter DEFAULT_DATE_TIME_PATTERN = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DEFAULT_DATE_PATTERN = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    public static final DateTimeFormatter DEFAULT_MONTH_PATTERN = DateTimeFormatter.ofPattern("yyyy-MM");
    public static final DateTimeFormatter DEFAULT_TIME_PATTERN = DateTimeFormatter.ofPattern("HH:mm:ss");

    private final Instant instant;

    private GameDateTime(@NotNull Instant instant) {
        this.instant = instant;
    }

    /**
     * 同时支持秒级和毫秒级时间戳
     *
     * @param timestamp
     * @return
     */
    public static GameDateTime of(@NotNull long timestamp) {
        if (timestamp > 1_000_000_000_000L) {
            return of(Instant.ofEpochMilli(timestamp));
        } else {
            return of(Instant.ofEpochSecond(timestamp));
        }
    }

    public static GameDateTime of(@NotNull Instant instant) {
        Assert.notNull(instant, "Instant参数不能为空");
        return new GameDateTime(instant);
    }

    public static GameDateTime of(@NotNull LocalDateTime dateTime) {
        Assert.notNull(dateTime, "LocalDateTime参数不能为空");
        return new GameDateTime(dateTime.toInstant(DEFAULT_ZONE_OFFSET));
    }

    public static GameDateTime of(@NotNull LocalDate date, @NotNull LocalTime time) {
        Assert.notNull(date, "LocalDate参数不能为空");
        Assert.notNull(time, "LocalTime参数不能为空");
        return new GameDateTime(LocalDateTime.of(date, time).toInstant(DEFAULT_ZONE_OFFSET));
    }

    public static GameDateTime of(@NotNull Date date) {
        Assert.notNull(date, "Jdk日期参数不能为空");
        return new GameDateTime(date.toInstant());
    }

    public static GameDateTime of(@NotNull DateTime dateTime) {
        Assert.notNull(dateTime, "Hutool日期参数不能为空");
        return new GameDateTime(dateTime.toInstant());
    }

    /**
     * 日期字符串格式必须为 yyyy-MM-dd HH:mm:ss
     *
     * @param dateTimeString
     * @return
     */
    public static GameDateTime of(@NotNull String dateTimeString) {
        Assert.notNull(dateTimeString, "日期字符串参数不能为空");
        return of(StringUtils.substringBefore(dateTimeString, "."), DEFAULT_DATE_TIME_PATTERN);
    }

    public static GameDateTime of(@NotNull String dateTimeString, @NotNull DateTimeFormatter formatter) {
        Assert.notNull(dateTimeString, "日期字符串参数不能为空");
        Assert.notNull(dateTimeString, "DateTimeFormatter参数不能为空");
        return of(LocalDateTime.parse(dateTimeString, formatter));
    }

    public static GameDateTime now() {
        return of(Instant.now());
    }

    public Date toJdkDate() {
        return Date.from(instant);
    }

    public Instant toInstant() {
        return instant;
    }

    public long toEpochMilli() {
        return instant.toEpochMilli();
    }

    public long toEpochSecond() {
        return instant.getEpochSecond();
    }

    public LocalDateTime toLocalDateTime() {
        return LocalDateTime.ofInstant(instant, DEFAULT_ZONE_ID);
    }

    public LocalDate toLocalDate() {
        return toLocalDateTime().toLocalDate();
    }

    public LocalTime toLocalTime() {
        return toLocalDateTime().toLocalTime();
    }

    public DateTime toHutoolDateTime() {
        return DateTime.of(toJdkDate());
    }

    public String toDateString() {
        return toLocalDate().format(DEFAULT_DATE_PATTERN);
    }

    /**
     * 示例：2000-07
     *
     * @return
     */
    public String toMonthString() {
        return toLocalDate().format(DEFAULT_MONTH_PATTERN);
    }

    public String toTimeString() {
        return toLocalTime().format(DEFAULT_TIME_PATTERN);
    }

    public String toDateTimeString() {
        return toLocalDateTime().format(DEFAULT_DATE_TIME_PATTERN);
    }

    public boolean isBefore(GameDateTime target) {
        Assert.notNull(target, "比较日期不能为空");
        return instant.isBefore(target.instant);
    }

    public boolean isBeforeOrEquals(GameDateTime target) {
        Assert.notNull(target, "比较日期不能为空");
        return instant.compareTo(target.instant) <= 0;
    }

    public boolean isAfter(GameDateTime target) {
        Assert.notNull(target, "比较日期不能为空");
        return instant.isAfter(target.instant);
    }

    public boolean isAfterOrEquals(GameDateTime target) {
        Assert.notNull(target, "比较日期不能为空");
        return instant.compareTo(target.instant) >= 0;
    }

    /**
     * 判断日期是否相同（仅比较日期，忽略时间部分）
     *
     * @param target
     * @return
     */
    public boolean equalsDate(GameDateTime target) {
        if (target == null) {
            return false;
        }
        return toLocalDate().isEqual(target.toLocalDate());
    }

    @Override
    public String toString() {
        return toDateTimeString();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        GameDateTime dateTime = (GameDateTime) o;
        return instant.equals(dateTime.instant);
    }

    @Override
    public int hashCode() {
        return Objects.hash(instant);
    }

}
